<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Point lighted cube (with animation)</title>
    <script src="lib/webgl-utils.js"></script>
    <script src="lib/webgl-debug.js"></script>
    <script src="lib/cuon-utils.js"></script>
    <script src="lib/cuon-matrix.js"></script>
    <style>
      body {
        border: 0;
        background-color: white;
      }
    </style>
  </head>

  <body onload="main()">
    <canvas id="webgl" style="width:900px;height: 900px;">
    Please use a browser that supports "canvas"
    </canvas>
  </body>
  <script>
    // 多个立方体  不旋转
var VSHADER_SOURCE =`
attribute vec4 a_Position;
attribute vec4 a_VertexPosition;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_ModelMatrix;
uniform mat4 u_NormalMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightPosition;
uniform vec3 u_AmbientLight;
varying vec4 v_Color;
//着色器程序针对每一个顶点执行
void main() {
  //计算点的位置
  gl_Position = u_MvpMatrix * a_Position;

  //物体的运动会导致表面的法向量方向发生变化，求出每个法向量在运动后的新值
  vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));

  // 单个点的位置
  vec4 vertexPosition = u_ModelMatrix * a_Position;

  //光线方向
  vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));

  //法向量和光线方向的点积
  float nDotL = max(dot(lightDirection, normal), 0.0);

  //反射光
  vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;

  // 环境光
  vec3 ambient = u_AmbientLight * a_Color.rgb;

  // 表面颜色
  v_Color = vec4(diffuse + ambient, a_Color.a);
}
`;

var FSHADER_SOURCE =`
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}`;

var VSHADER_SOURCE2=`
attribute vec4 a_VertexPosition;
uniform mat4 u_MvpMatrix2;
void main(){
gl_Position=u_MvpMatrix2 * a_VertexPosition;
}
`;
var FSHADER_SOURCE2=`
void main(){
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
`;

var vertices,normals,indices,colors, cubeLength=0.3,pointArray=[],translateCube,canvas,n,positionAttrib,colorAttrib,normalAttrib,edgeAttribute,u_LightColor,u_LightPosition,u_AmbientLight;
      function main() {

          canvas = document.getElementById('webgl');
          // 获取浏览器中画布的显示尺寸
          var displayWidth  = canvas.clientWidth;
          var displayHeight = canvas.clientHeight;
          if (canvas.width  !== displayWidth || canvas.height !== displayHeight) {
              canvas.width  = displayWidth;
              canvas.height = displayHeight;
          }


          var gl=getWebGLContext(canvas);
          // var gl = canvas.getContext('webgl',
          //     { antialias: true });
          if(!gl){
              console.log('无法获取webGL绘图环境');
              return;
          }
          gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
          gl.clearColor(0.0, 0.0, 0.0, 1.0);
          gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);


          var surfaceProgram=createProgram(gl,VSHADER_SOURCE,FSHADER_SOURCE);
          var edgeProgram=createProgram(gl,VSHADER_SOURCE2,FSHADER_SOURCE2);
          if(!surfaceProgram||!edgeProgram){
              console.log('创建程序对象失败');
              return;
          }

          gl.enable(gl.DEPTH_TEST);
          var start=new Date().getTime()
          for(var i=0;i<5000;i++){
              drawCube(gl,surfaceProgram,i);
              drawLine(gl,edgeProgram);
          }
          console.log(new Date().getTime()-start)

      }

      function drawCube(gl,surfaceProgram,i){
          gl.useProgram(surfaceProgram);
          // if(n==undefined){
              n = initVertexBuffers(gl,surfaceProgram);
              if (n < 0) {
                  console.log('Failed to set the vertex information');
                  return;
              }
          // }
          if(i==0){
               u_LightColor = gl.getUniformLocation(surfaceProgram, 'u_LightColor');
               u_LightPosition = gl.getUniformLocation(surfaceProgram, 'u_LightPosition');
               u_AmbientLight = gl.getUniformLocation(surfaceProgram, 'u_AmbientLight');
          }
          gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
          gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
          gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);


          // Get the storage locations of uniform variables and so on
          var u_ModelMatrix = gl.getUniformLocation(surfaceProgram, 'u_ModelMatrix');
          var u_MvpMatrix = gl.getUniformLocation(surfaceProgram, 'u_MvpMatrix');
          var u_NormalMatrix = gl.getUniformLocation(surfaceProgram, 'u_NormalMatrix');
          // var u_LightColor = gl.getUniformLocation(surfaceProgram, 'u_LightColor');
          // var u_LightPosition = gl.getUniformLocation(surfaceProgram, 'u_LightPosition');
          // var u_AmbientLight = gl.getUniformLocation(surfaceProgram, 'u_AmbientLight');
          // if (!u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition　|| !u_AmbientLight) {
          //     console.log('Failed to get the storage location');
          //     return;
          // }

          // gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
          // gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
          // gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
          var modelMatrix = new Matrix4();  // Model matrix
          var mvpMatrix = new Matrix4();    // Model view projection matrix
          var normalMatrix = new Matrix4(); // Transformation matrix for normals
          modelMatrix.setRotate(90, 0, 1, 0); // Rotate around the y-axis

          translateCube={
              x:i-3,
              y:0,
              z:0
          };
          modelMatrix.setTranslate(translateCube.x,translateCube.y,translateCube.z);
          gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

          mvpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
          mvpMatrix.lookAt(0, 6, 20, 0, 0, 0, 0, 1, 0);
          mvpMatrix.multiply(modelMatrix);
          gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

          normalMatrix.setInverseOf(modelMatrix);
          normalMatrix.transpose();
          gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);

          gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

      }

      function drawLine(gl,edgeProgram){
          gl.useProgram(edgeProgram);
          //画edge先的部分
          if(pointArray.length==0){
              getPointsArray();
              edgeAttribute=initArrayBuffer(gl,'a_VertexPosition', new Float32Array(pointArray), 3, gl.FLOAT,edgeProgram)
              // if(!initArrayBuffer(gl,'a_VertexPosition', new Float32Array(pointArray), 3, gl.FLOAT,edgeProgram)) return -1;
          }/*else{
              // gl.enableVertexAttribArray(edgeAttribute);
          }*/
          var u_MvpMatrix2 = gl.getUniformLocation(edgeProgram, 'u_MvpMatrix2');
          if(!u_MvpMatrix2){
              console.log('Failed to get the storage location');
              return;
          }
          var modelMatrix2 = new Matrix4();  // Model matrix
          var mvpMatrix2 = new Matrix4();    // Model view projection matrix
          modelMatrix2.setTranslate(translateCube.x,translateCube.y,translateCube.z);

          mvpMatrix2.setPerspective(30, canvas.width/canvas.height, 1, 100);
          mvpMatrix2.lookAt(0, 6, 20, 0, 0, 0, 0, 1, 0);
          mvpMatrix2.multiply(modelMatrix2);
          gl.uniformMatrix4fv(u_MvpMatrix2, false, mvpMatrix2.elements);
          gl.drawArrays(gl.LINES,0,pointArray.length/3);

      }
      function getPointsArray(){
          var edge = [ 0, 0 ], edges = {}, edge1, edge2;
          var key, keys = [ 'a', 'b', 'c' ];
          for(var i=0,l=indices.length;i<l;i=i+3){
              var face={a:indices[i],b:indices[i+1],c:indices[i+2]};

              var normal=[normals[i],normals[i+1],normals[i+2]];

              for(var j=0;j<3;j++){
                  edge1=face[keys[j]];
                  edge2=face[keys[(j+1)%3]];
                  edge[ 0 ] = Math.min( edge1, edge2 );
                  edge[ 1 ] = Math.max( edge1, edge2 );
                  key = edge[ 0 ] + ',' + edge[ 1 ];
                  if ( edges[ key ] === undefined ) {
                      edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1:face , face2: undefined };
                  } else {
                      edges[ key ].face2 = face;
                  }
              }
              // console.log(edges)
          }

          pointArray=[];
          for(key in edges){
              var e=edges[key];
              if(e.face2 === undefined) {
                  pointArray.push(vertices[e.index1*3],vertices[e.index1*3+1],vertices[e.index1*3+2]);
                  pointArray.push(vertices[e.index2*3],vertices[e.index2*3+1],vertices[e.index2*3+2]);
              }else{
                  //e.face1.a ==>indices数组中顶点的索引
                  //p1 ==> 顶点
                  var p1={x:vertices[(e.face1.a)*3],y:vertices[(e.face1.a)*3+1],z:vertices[(e.face1.a)*3+2]};
                  var p2={x:vertices[(e.face1.b)*3],y:vertices[(e.face1.b)*3+1],z:vertices[(e.face1.b)*3+2]};
                  var p3={x:vertices[(e.face1.c)*3],y:vertices[(e.face1.c)*3+1],z:vertices[(e.face1.c)*3+2]};

                  var q1={x:vertices[(e.face2.a)*3],y:vertices[(e.face2.a)*3+1],z:vertices[(e.face2.a)*3+2]};
                  var q2={x:vertices[(e.face2.b)*3],y:vertices[(e.face2.b)*3+1],z:vertices[(e.face2.b)*3+2]};
                  var q3={x:vertices[(e.face2.c)*3],y:vertices[(e.face2.c)*3+1],z:vertices[(e.face2.c)*3+2]};
                  var face1Normal=getNormal(p1,p2,p3).elements;
                  var face2Normal=getNormal(q1,q2,q3).elements;
                  var dot=face1Normal[0]*face2Normal[0]+face1Normal[1]*face2Normal[1]+face1Normal[2]*face2Normal[2];
                  if(dot<1){
                      pointArray.push(vertices[e.index1*3],vertices[e.index1*3+1],vertices[e.index1*3+2]);
                      pointArray.push(vertices[e.index2*3],vertices[e.index2*3+1],vertices[e.index2*3+2]);
                  }

              }
          }
      }

      function getNormal(p1,p2,p3){
          var a = ( (p2.y - p1.y) * (p3.z - p1.z) - (p2.z - p1.z) * (p3.y - p1.y) );

          var b = ( (p2.z - p1.z) * (p3.x - p1.x) - (p2.x - p1.x) * (p3.z - p1.z) );

          var c = ( (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) );

          var normal=new Vector3([a,b,c])
          return normal.normalize();
      }

      function initVertexBuffers(gl,program) {
          // Create a cube
          //    v6----- v5
          //   /|      /|
          //  v1------v0|
          //  | |     | |
          //  | |v7---|-|v4
          //  |/      |/
          //  v2------v3
          // Coordinates

           if(vertices==undefined){
          vertices = new Float32Array([
              cubeLength, cubeLength, cubeLength,  -cubeLength, cubeLength, cubeLength,  -cubeLength,-cubeLength, cubeLength,   cubeLength,-cubeLength, cubeLength, // v0-v1-v2-v3 front
              cubeLength, cubeLength, cubeLength,   cubeLength,-cubeLength, cubeLength,   cubeLength,-cubeLength,-cubeLength,   cubeLength, cubeLength,-cubeLength, // v0-v3-v4-v5 right
              cubeLength, cubeLength, cubeLength,   cubeLength, cubeLength,-cubeLength,  -cubeLength, cubeLength,-cubeLength,  -cubeLength, cubeLength, cubeLength, // v0-v5-v6-v1 up
              -cubeLength, cubeLength, cubeLength,  -cubeLength, cubeLength,-cubeLength,  -cubeLength,-cubeLength,-cubeLength,  -cubeLength,-cubeLength, cubeLength, // v1-v6-v7-v2 left
              -cubeLength,-cubeLength,-cubeLength,   cubeLength,-cubeLength,-cubeLength,   cubeLength,-cubeLength, cubeLength,  -cubeLength,-cubeLength, cubeLength, // v7-v4-v3-v2 down
              cubeLength,-cubeLength,-cubeLength,  -cubeLength,-cubeLength,-cubeLength,  -cubeLength, cubeLength,-cubeLength,   cubeLength, cubeLength,-cubeLength  // v4-v7-v6-v5 back
          ]);

          // Colors
           colors = new Float32Array([
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v1-v2-v3 front
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v3-v4-v5 right
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v5-v6-v1 up
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v1-v6-v7-v2 left
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v7-v4-v3-v2 down
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0　    // v4-v7-v6-v5 back
          ]);

          // Normal
           normals = new Float32Array([
              0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
              1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
              0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
              -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
              0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,  // v7-v4-v3-v2 down
              0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0   // v4-v7-v6-v5 back
          ]);

          // Indices of the vertices
          indices = new Uint8Array([
              0, 1, 2,   0, 2, 3,    // front
              4, 5, 6,   4, 6, 7,    // right
              8, 9,10,   8,10,11,    // up
              12,13,14,  12,14,15,    // left
              16,17,18,  16,18,19,    // down
              20,21,22,  20,22,23     // back
          ]);
               positionAttrib=initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT,program);
               colorAttrib=initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT,program)
               normalAttrib=initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT,program)

               // Unbind the buffer object
               // gl.bindBuffer(gl.ARRAY_BUFFER, null);
               // Write the indices to the buffer object
               var indexBuffer = gl.createBuffer();
               if (!indexBuffer) {
                   console.log('Failed to create the buffer object');
                   return false;
               }
               gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
               gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
               return indices.length;
           }else{
               // gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
               gl.enableVertexAttribArray(positionAttrib);
               gl.enableVertexAttribArray(colorAttrib);
               gl.enableVertexAttribArray(normalAttrib);
               // initAttributeVariable(gl,a_Position,)
               return indices.length;

           }
      }

      function initArrayBuffer(gl, attribute, data, num, type,program) {
          // Create a buffer object
          var buffer = gl.createBuffer();
          if (!buffer) {
              console.log('Failed to create the buffer object');
              return false;
          }
          // Write date into the buffer object
          gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
          gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
          // Assign the buffer object to the attribute variable
          var a_attribute = gl.getAttribLocation(program, attribute);
          if (a_attribute < 0) {
              console.log('Failed to get the storage location of ' + attribute);
              return false;
          }
          gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
          // Enable the assignment of the buffer object to the attribute variable
          gl.enableVertexAttribArray(a_attribute);

          return a_attribute;
      }
function initAttributeVariable(gl, a_attribute, buffer) {
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
    gl.enableVertexAttribArray(a_attribute);
}




  </script>
</html>
